﻿using Fizzler.Systems.HtmlAgilityPack;
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace HuaJuanAudioNevolDown
{
    public class ExtraYuetingbaCn : IExtractor
    {
        public string Site => "http://www.yuetingba.cn";

        readonly byte[] AES_KEY = Convert.FromBase64String("le95G3hnFDJsBE+1/v9eYw==");
        readonly byte[] AES_IV = Convert.FromBase64String("IvswQFEUdKYf+d1wKpYLTg==");

        string siteSearchPath = "/Search?type={0}&name={1}";
        string reqMp3UrlTpl = "/api/app/docs-listen/{0}/ting-with-ef";

        public Form _form { get; set; }
        public DataTable _novelData { get; set; }

        public ToolStripProgressBar _pbRequestProcess { get; set; }

        public string NovelName { get; set; }

        public string NovelRealHost { get; set; }

        private readonly HttpClient _httpClient = new HttpClient();

        public async Task ExtractAudioLinksAsync(string novelName, string url)
        {
            // 取得书名
            this.NovelName = novelName;

            int index = 0;

            // 取得域名网址
            string host = Utils.GetHost(url);

            // 取得root doc node
            var docNode = GetDocumentNode(url);

            this.NovelRealHost = GetAudioNovelRealHost(docNode);

            // 取得 Pages Node
            var tingNode = GetTingNode(docNode);

            // 取得所有分页数据(每页200集)
            List<PageInfo> pages = GetPages(tingNode);

            _pbRequestProcess.Minimum = 0;
            _pbRequestProcess.Maximum = pages.Count;
            // 循环每一页
            for (int i = 0; i < pages.Count; i++)
            {
                var page = pages[i];
                string partUrl = host + page.Link;
                var node = GetDocumentNode(partUrl);
                var pNode = GetTingNode(node);
                var chapters = GetChapterLinks(pNode);

                // 循环每个章节模拟获取MP3链接
                for (int j = 0; j < chapters.Count; j++)
                {
                    index++;
                    var info = chapters[j];
                    UpdateListView(index, page.Name, info.AudioName, info.ReqAudioUrl, info.RealAudioUrl, ExtractorStatus.Waiting.GetDescription());
                }
                _pbRequestProcess.Value = i + 1;
                await Task.Delay(50);
            }

            _pbRequestProcess.Minimum = 0;
            _pbRequestProcess.Maximum = _novelData.Rows.Count;

            // 用于存放和控制并发任务的列表
            List<Task> taskList = new List<Task>();
            int maxConcurrentTasks = 10;

            for (int j = 0; j < _novelData.Rows.Count; j++)
            {
                DataRow row = _novelData.Rows[j];
                string realUrl = "";

                if (taskList.Count >= maxConcurrentTasks)
                {
                    Task completedTask = await Task.WhenAny(taskList);
                    taskList.Remove(completedTask);

                    UpdateProgressBar(j + 1);
                }

                var task = Task.Run(async () =>
                {
                    // 正常一次+重试两次，共计3次
                    for (int k = 0; k < 3; k++)
                    {
                        realUrl = await GetMp3UrlAsync(row["ReqAddress"].ToString());
                        lock (_novelData)
                        {
                            if (realUrl == "")
                            {
                                row["ExtractorStatus"] = ExtractorStatus.Failure.GetDescription();
                                continue;
                            }
                            else
                            {
                                row["RealAddress"] = Uri.EscapeUriString(NovelRealHost + realUrl);
                                row["ExtractorStatus"] = ExtractorStatus.Sucess.GetDescription();
                                break;
                            }
                        }
                    }
                    //_pbRequestProcess.Value = j + 1;
                });
                taskList.Add(task);
            }
            await Task.WhenAll(taskList);
            UpdateProgressBar(_novelData.Rows.Count);
        }

        private void UpdateProgressBar(int value)
        {
            if (_form.InvokeRequired)
            {
                _form.Invoke(new Action(() => _pbRequestProcess.Value = value));
            }
            else
            {
                _pbRequestProcess.Value = value;
            }
        }

        public async Task ReExtractAudioLinksAsync(DataGridViewSelectedRowCollection SelectedRows)
        {
            for (int j = 0; j < SelectedRows.Count; j++)
            {
                DataGridViewRow row = SelectedRows[j];

                string realUrl = "";
                if (row.Cells["ExtractorStatus"].Value.ToString() != ExtractorStatus.Sucess.GetDescription())
                {
                    // 正常一次+重试两次，共计3次
                    for (int k = 0; k < 3; k++)
                    {
                        realUrl = await GetMp3UrlAsync(row.Cells["ReqAddress"].Value.ToString());
                        if (realUrl == "")
                        {
                            row.Cells["ExtractorStatus"].Value = ExtractorStatus.Failure.GetDescription();
                            continue;
                        }
                        else
                        {
                            row.Cells["RealAddress"].Value = Uri.EscapeUriString(NovelRealHost + realUrl);
                            row.Cells["ExtractorStatus"].Value = ExtractorStatus.Sucess.GetDescription();
                            break;
                        }
                    }
                }
                await Task.Delay(50);
            }
        }

        public async Task<List<SearchResultInfo>> Search(string searchtype, string searchword)
        {
            List<SearchResultInfo> searchResultInfos = new List<SearchResultInfo>();
            var url = $"{Site}{siteSearchPath.Replace("{0}", "1").Replace("{1}", searchword)}";
            url = Uri.EscapeUriString(url);
            // 取得root doc node
            var docNode = GetDocumentNode(url);

            var resultListNode = docNode.QuerySelectorAll(".box-list-item-text").ToList();

            if (resultListNode.Count > 0)
            {
                for (int i = 0; i < resultListNode.Count; i++)
                {
                    var node = resultListNode[i];

                    // 提取书名和链接
                    var titleNode = node.QuerySelector(".box-list-item-text-title a");
                    string novelName = titleNode.InnerText.Trim();
                    string novelAddress = titleNode.GetAttributeValue("href", "").Trim();

                    // 提取作者
                    var authorNode = node.QuerySelector(".lnr-user + span a");
                    string novelAuthor = authorNode.InnerText.Trim();

                    // 提取主播
                    var anchorNode = node.QuerySelector(".lnr-mic + span a");
                    string NovelAnchor = anchorNode.InnerText.Trim();

                    // 提取简介
                    var introNode = node.QuerySelector(".box-list-item-text-intro");
                    string intro = introNode.InnerText.Trim();

                    searchResultInfos.Add(new SearchResultInfo()
                    {
                        Site = this.Site,
                        NovelName = novelName,
                        NovelAuthor = novelAuthor,
                        NovelAnchor = NovelAnchor,
                        NovelAddress = Site + novelAddress,
                        Novelintro = intro,
                    });
                    await Task.Delay(1);
                }
            }
            return searchResultInfos;
        }

        /// <summary>
        /// 取得document DOM节点
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private HtmlNode GetDocumentNode(string url)
        {
            var web = new HtmlWeb();
            var doc = web.Load(url);
            return doc.DocumentNode;
        }

        /// <summary>
        /// 取得小说名
        /// </summary>
        /// <param name="docNode"></param>
        /// <returns>小说名</returns>
        private string GetNovelName(HtmlNode docNode)
        {
            HtmlNode bookDetail = docNode.QuerySelector(".books-detail-detail").QuerySelector(".hidden-xs");
            var novelName = bookDetail.InnerText;
            novelName = Regex.Replace(novelName, "\r\n", "");
            novelName = novelName.Trim();
            return novelName;
        }

        /// <summary>
        /// 取得小说音频 DOM节点
        /// </summary>
        /// <param name="docNode"></param>
        /// <returns></returns>
        private HtmlNode GetTingNode(HtmlNode docNode)
        {
            return docNode.QuerySelector(".ting-list");
        }

        /// <summary>
        /// 取得分页的页面信息
        /// </summary>
        /// <param name="tingNode"></param>
        /// <returns>全部页</returns>
        private List<PageInfo> GetPages(HtmlNode tingNode)
        {
            List<HtmlNode> pageNodes = tingNode.QuerySelectorAll("ul a").ToList();
            List<PageInfo> pages = new List<PageInfo>();

            foreach (var node in pageNodes)
            {
                var link = node.GetAttributeValue("href", "");
                var name = node.InnerText;
                pages.Add(new PageInfo() { Name = name, Link = link });
            }
            return pages;
        }

        private void UpdateListView(int index, string chatper, string chapterName, string reqUrl, string mp3Url, string status)
        {
            DataRow row = _novelData.NewRow();
            row["Index"] = index.ToString();
            row["ChapterName"] = chapterName;
            row["ReqAddress"] = reqUrl;
            row["RealAddress"] = mp3Url;
            row["ExtractorStatus"] = status;
            _novelData.Rows.Add(row);
        }

        private List<ChapterInfo> GetChapterLinks(HtmlNode htmNode)
        {
            List<ChapterInfo> Mp3InfoList = new List<ChapterInfo>();
            List<HtmlNode> item = htmNode.QuerySelectorAll(".ting-list-content-item").ToList();

            for (int i = 0; i < item.Count; i++)
            {
                var node = item[i];
                string val = node.GetAttributeValue("id", "");
                string name = node.InnerText;
                name = Regex.Replace(name, "<!--.*-->", "");
                name = Regex.Replace(name, "\r\n", "");
                name = name.Trim();
                if (name == "")
                {
                    name = "0000";
                }
                val = val.Replace("item_", "");
                Mp3InfoList.Add(new ChapterInfo()
                {
                    ReqAudioUrl = Site + reqMp3UrlTpl.Replace("{0}", val),
                    AudioName = name
                });
            }
            return Mp3InfoList;
        }

        public async Task<string> GetMp3UrlAsync(string url)
        {
            string realUrl = "";
            // 发送 GET 请求
            var response = await _httpClient.GetAsync(url);

            if (response.IsSuccessStatusCode)
            {
                // 读取响应内容
                var jsonResponse = await response.Content.ReadAsStringAsync();
                // 反序列化 JSON 响应
                var resp = JsonSerializer.Deserialize<ResponseInfo>(jsonResponse);

                // 解密并获取真实的 MP3 URL
                if (resp != null)
                {
                    realUrl = Utils.Decrypt(resp.ef, AES_KEY, AES_IV);
                }
            }
            else
            {
                Console.WriteLine($"请求失败: {response.StatusCode}");
            }
            return realUrl;
        }

        public string GetAudioNovelRealHost(HtmlNode docNode)
        {
            var text = docNode.InnerHtml;
            var ptn = "assl = '.*'";

            var match = Regex.Match(text, ptn);
            var assl = "";
            var realHost = "";
            if (match.Success)
            {
                assl = match.Value;
                assl = assl.Replace("assl =", "");
                assl = assl.Replace("'", "");
                var json = Utils.Decrypt(assl, AES_KEY, AES_IV);
                var sslInfos = JsonSerializer.Deserialize<List<SslInfo>>(json);
                var sslInfo = sslInfos[1];
                realHost = $"{sslInfo.Scheme}://{sslInfo.Value}:{sslInfo.Port}";
            }
            return realHost;
        }
    }
}
